import * as XLSX from 'xlsx'
import { saveAs } from 'file-saver'
import type {
  ResultsItem,
  Results,
  Header,
  JsonToExcelData,
  Cell,
  Ws
} from './types'
import { useAnalysisStore } from '@/stores/index'
const analysisStore = useAnalysisStore()

/**
 *
 * @param rawFile Eecel文件File对象
 * @returns Promise<{ header: string[]; dataResult: Results }>
 */
const useAnalysisExcel = (rawFile: File) => {
  return new Promise<{ header: string[]; dataResult: Results }>(
    (resolve, reject) => {
      const reader = new FileReader()
      //读取文件
      reader.readAsArrayBuffer(rawFile)
      //文件加载完成后
      reader.onload = (e) => {
        const data = e.target?.result
        const workbook = XLSX.read(data, { type: 'array' })
        const firstSheetName = workbook.SheetNames[0]
        const worksheet: XLSX.WorkSheet = workbook.Sheets[firstSheetName]
        const header: Header = getHeaderRow(worksheet)
        const results: Results = XLSX.utils.sheet_to_json(worksheet)
        const dataResult: Results = handleExcelData(results)
        resolve({ header, dataResult })
      }
      reader.onerror = (error) => {
        reject(error)
      }
    }
  )
}
//获取表格header
const getHeaderRow = (sheet: XLSX.WorkSheet) => {
  const headers = []
  const range = XLSX.utils.decode_range(sheet['!ref']!) //最大列
  let C
  const R = range.s.r //start row0  起始行
  /* start in the first row */
  for (C = range.s.c; C <= range.e.c; ++C) {
    /* walk every column in the range */
    const cell = sheet[XLSX.utils.encode_cell({ c: C, r: R })]
    /* find the cell in the first row */
    let hdr = 'UNKNOWN ' + C // <-- replace with your desired default
    //格式化单元格
    if (cell && cell.t) hdr = XLSX.utils.format_cell(cell)
    headers.push(hdr)
  }
  return headers
}
// 封装处理上传的Excel中中文字段转英文字段的函数
const handleExcelData = (results: Results) => {
  return results.map((item) => {
    const obj: ResultsItem = {} as unknown as ResultsItem
    for (const [key, value] of Object.entries(analysisStore.excelMapState)) {
      obj[key] = item[value]
    }
    return obj
  })
}
/**
 * 导出表格数据为Excel文件
 * @param {
 * multiHeader //多级表头数组
 *header //表头
 *data //数据数组
 *filename //导出Excel名字
 *merges //合并表头数组
 *autoWidth 自动单元格宽度
 *bookType = 导出表格类型 'xlsx|xls'
 * }
 * @return void
 */
const useDownloadExcel = ({
  multiHeader = [],
  header = Object.values(analysisStore.excelMapState),
  data,
  filename,
  merges = [],
  autoWidth = true,
  bookType = 'xlsx'
}: JsonToExcelData) => {
  /* original data */
  filename = filename || 'excel-list'
  data = [...data]
  data.unshift(header) //前部插入表头

  // 前部插入多级表头
  for (let i = multiHeader.length - 1; i > -1; i--) {
    data.unshift(multiHeader[i])
  }

  const ws_name = 'SheetJS'
  const wb = new Workbook()
  const ws = sheet_from_array_of_arrays(data)

  if (merges.length > 0) {
    if (!ws['!merges']) ws['!merges'] = []
    merges.forEach((item) => {
      ws['!merges'].push(XLSX.utils.decode_range(item))
    })
  }

  if (autoWidth) {
    /*设置worksheet每列的最大宽度*/
    const colWidth = data.map((row) =>
      row.map((val) => {
        /*先判断是否为null/undefined*/
        if (val == null) {
          return {
            wch: 10
          }
        } else if (val.toString().charCodeAt(0) > 255) {
          /*再判断是否为中文*/
          return {
            wch: val.toString().length * 2
          }
        } else {
          return {
            wch: val.toString().length
          }
        }
      })
    )
    /*以第一行为初始值*/
    const result = colWidth[0]
    for (let i = 1; i < colWidth.length; i++) {
      for (let j = 0; j < colWidth[i].length; j++) {
        if (result[j]['wch'] < colWidth[i][j]['wch']) {
          result[j]['wch'] = colWidth[i][j]['wch']
        }
      }
    }
    ws['!cols'] = result
  }

  /* add worksheet to workbook */
  wb.SheetNames.push(ws_name)
  wb.Sheets[ws_name] = ws

  const wbout = XLSX.write(wb, {
    bookType: bookType,
    bookSST: false,
    type: 'binary'
  })
  saveAs(
    new Blob([s2ab(wbout)], {
      type: 'application/octet-stream'
    }),
    `${filename}.${bookType}`
  )
}
function datenum(v: any, date1904?: number) {
  if (date1904) v += 1462
  const epoch = Date.parse(v)
  return (
    (epoch - new Date(Date.UTC(1899, 11, 30)).getTime()) / (24 * 60 * 60 * 1000)
  )
}
function sheet_from_array_of_arrays(data: Array<Array<any>>) {
  const ws: Ws = {} as unknown as Ws
  const range = {
    s: {
      c: 10000000,
      r: 10000000
    },
    e: {
      c: 0,
      r: 0
    }
  }
  for (let R = 0; R != data.length; ++R) {
    for (let C = 0; C != data[R].length; ++C) {
      if (range.s.r > R) range.s.r = R
      if (range.s.c > C) range.s.c = C
      if (range.e.r < R) range.e.r = R
      if (range.e.c < C) range.e.c = C
      const cell: Cell = {
        v: data[R][C]
      }
      if (cell.v == null) continue
      const cell_ref = XLSX.utils.encode_cell({
        c: C,
        r: R
      })

      if (typeof cell.v === 'number') cell.t = 'n'
      else if (typeof cell.v === 'boolean') cell.t = 'b'
      else if (cell.v instanceof Date) {
        cell.t = 'n'
        cell.z = XLSX.SSF._table[14]
        cell.v = datenum(cell.v)
      } else cell.t = 's'

      ws[cell_ref] = cell
    }
  }
  if (range.s.c < 10000000) ws['!ref'] = XLSX.utils.encode_range(range)
  return ws
}
// 使用类改写原工厂函数
class Workbook {
  SheetNames: Array<string>
  Sheets: { [key: string]: Ws }
  constructor(SheetNames = [], Sheets = {}) {
    this.SheetNames = SheetNames
    this.Sheets = Sheets
  }
}
function s2ab(s: any) {
  const buf = new ArrayBuffer(s.length)
  const view = new Uint8Array(buf)
  for (let i = 0; i != s.length; ++i) view[i] = s.charCodeAt(i) & 0xff
  return buf
}
export { useAnalysisExcel, useDownloadExcel }
